#include <cassi/CASSIE.h>

// ***********************************************************************

// class EDROOMTopContext

// ***********************************************************************



	// CONSTRUCTORES***********************************************

CASSI::EDROOMTopContext::EDROOMTopContext (CASSI &act, bool_t & EDROOMpVarVBidirectional, bool_t & EDROOMpVarVCrcOk, CDFrame & EDROOMpVarVDataFrame, FrameTypeReceived_t & EDROOMpVarVFrameType, CDSignal & EDROOMpVarVSignalFrame, CEDROOMPOOLCDSignal & EDROOMpPoolCDSignal, CEDROOMPOOLCDFrame & EDROOMpPoolCDFrame ):

	EDROOMcomponent(act)
	,Msg(EDROOMcomponent.Msg)
	,MsgBack(EDROOMcomponent.MsgBack)
	,SsiCtrl(EDROOMcomponent.SsiCtrl)
	,Ssi(EDROOMcomponent.Ssi)
	,StoreAndNextFrame(EDROOMcomponent.StoreAndNextFrame)
	, VBidirectional ( EDROOMpVarVBidirectional )
	, VCrcOk ( EDROOMpVarVCrcOk )
	, VDataFrame ( EDROOMpVarVDataFrame )
	, VFrameType ( EDROOMpVarVFrameType )
	, VSignalFrame ( EDROOMpVarVSignalFrame )
	, EDROOMPoolCDSignal ( EDROOMpPoolCDSignal )
	, EDROOMPoolCDFrame ( EDROOMpPoolCDFrame )
 {

}

CASSI::EDROOMTopContext::EDROOMTopContext ( EDROOMTopContext &contex ):

	EDROOMcomponent(contex.EDROOMcomponent),
	Msg(contex.Msg),
	MsgBack(contex.MsgBack)
	,SsiCtrl(contex.SsiCtrl)
	,Ssi(contex.Ssi)
	,StoreAndNextFrame(contex.StoreAndNextFrame)
	, VBidirectional ( contex.VBidirectional )
	, VCrcOk ( contex.VCrcOk )
	, VDataFrame ( contex.VDataFrame )
	, VFrameType ( contex.VFrameType )
	, VSignalFrame ( contex.VSignalFrame )
	, EDROOMPoolCDSignal ( contex.EDROOMPoolCDSignal )
	, EDROOMPoolCDFrame ( contex.EDROOMPoolCDFrame )
 {

}

	// EDROOMSearchContextTrans********************************************

bool CASSI::EDROOMTopContext::EDROOMSearchContextTrans(TEDROOMTransId &edroomCurrentTrans){

	bool edroomValidMsg=false; 

	 switch(Msg->signal){

		 case ( EDROOMSignalDestroy ): 

			 edroomValidMsg=true;
			 edroomCurrentTrans.distanceToContext = 0 ;
			 edroomCurrentTrans.localId = -1 ;
			 break;

	}

	return(edroomValidMsg);

}

	// Funciones Definidas por el usuario  ****************************

void	CASSI::EDROOMTopContext::FDataConfirmed()

{
 
	CDSignal * ap_CDSignal = EDROOMPoolCDSignal.AllocData();
	
	// Complete Data
	(*ap_CDSignal)= VSignalFrame;
	
	// send new Msg
	StoreAndNextFrame.send(SSignalFrame, EDROOMprioNormal, ap_CDSignal, &EDROOMPoolCDSignal);
		// send new Msg
	
FMsgCommited();
}
 



void	CASSI::EDROOMTopContext::FMoreData()

{
	CDFrame & varCDFrame = *(CDFrame *)Msg->data;
 	CDFrame * ap_CDFrame = EDROOMPoolCDFrame.AllocData();
 
	// Complete Data
	(*ap_CDFrame)=varCDFrame;
 
	// send new Msg
	Ssi.send(SDataFrame, EDROOMprioNormal, ap_CDFrame, &EDROOMPoolCDFrame);
}



void	CASSI::EDROOMTopContext::FMsgCommited()

{
		// send new Msg
	
	Ssi.send(SMsgCommited, EDROOMprioNormal);
 
 
 
 
 
}



void	CASSI::EDROOMTopContext::FNoMoreData()

{
	CDSignal & varCDSignal = *(CDSignal *)Msg->data;
 	CDSignal * ap_CDSignal = EDROOMPoolCDSignal.AllocData();
 
	// Complete Data
	(*ap_CDSignal)=varCDSignal;
	// send new Msg
	Ssi.send(SSignalFrame, EDROOMprioNormal, ap_CDSignal, &EDROOMPoolCDSignal);
}
 



void	CASSI::EDROOMTopContext::FReceiveData()

{
	CDFrame & varCDFrame = *(CDFrame *)Msg->data;
	
	VDataFrame=varCDFrame;
	//crc
	VCrcOk=ssi_link_layer_check_data_frame_crc(VDataFrame.dataFrame);
	VBidirectional=ssi_link_layer_sensor_id_is_bidirectional(ssi_link_layer_get_sensor_id(VDataFrame.dataFrame));
	
	if (VBidirectional)//It can be Discovery(Beacon) or Data
	{
		VFrameType=ssi_link_layer_get_frame_type(VDataFrame.dataFrame);
	}
	else
	{
		VFrameType=FrameTypeIsSSIUnidirectional;
	}
}



void	CASSI::EDROOMTopContext::FReceiveSignal()

 
{
 	VFrameType=FrameTypeIsSSIDefault;
	CDSignal & varCDSignal = *(CDSignal *)Msg->data;
 
	VSignalFrame=varCDSignal;
	VCrcOk=ssi_link_layer_check_signal_frame_crc(VSignalFrame.signalFrame);
	VBidirectional=ssi_link_layer_sensor_id_is_bidirectional(ssi_link_layer_get_sensor_id(VSignalFrame.signalFrame));
 
	if (VBidirectional)//It can be Discovery(Beacon) or Data
	{
		VFrameType=ssi_link_layer_get_frame_type(VSignalFrame.signalFrame);
	}
 
 
}



void	CASSI::EDROOMTopContext::FRequestNextFrame()

{
 
 	// send new Msg
 	//request next data frame to descent communication
	StoreAndNextFrame.send(SNextSensorSsiDataFrame, EDROOMprioNormal);
 
}



void	CASSI::EDROOMTopContext::FSendFrameUnidirectional()

{
 
	CDFrame * ap_CDFrame = EDROOMPoolCDFrame.AllocData();
 
	(*ap_CDFrame)=VDataFrame;
	// send new Msg
	StoreAndNextFrame.send(SDataFrame, EDROOMprioNormal, ap_CDFrame, &EDROOMPoolCDFrame);
		// send new Msg
	
	FMsgCommited();
}
 



void	CASSI::EDROOMTopContext::FSendToStoreFrame()

 
{
	DEBUG("SSI\n");
 
	CDFrame * ap_CDFrame = EDROOMPoolCDFrame.AllocData();
 
	// Complete Data
	(*ap_CDFrame)=VDataFrame;
	// send new Msg
	StoreAndNextFrame.send(SDataFrame, EDROOMprioNormal, ap_CDFrame, &EDROOMPoolCDFrame);
 
}
 



void	CASSI::EDROOMTopContext::FToListening()

{
 
	FMsgCommited();
 
}
 



bool_t	CASSI::EDROOMTopContext::GIsAck()

{
	DEBUG("SSI\n");
 return (VCrcOk && (VFrameType==FrameTypeIsSSIAck));
}



bool_t	CASSI::EDROOMTopContext::GIsData()

{
	DEBUG("SSI\n");
return (VCrcOk && (VFrameType==FrameTypeIsSSIData));
}



bool_t	CASSI::EDROOMTopContext::GIsDiscovery()

{
	DEBUG("SSI\n");
 return (VCrcOk && (VFrameType==FrameTypeIsSSIDiscovery));
}



bool_t	CASSI::EDROOMTopContext::GIsUnidirectional()

{
	DEBUG("SSI\n");
 return (VCrcOk && (VFrameType==FrameTypeIsSSIUnidirectional));
}
 



	//*****Pools

	//CEDROOMPOOLCDSignal

CASSI::EDROOMTopContext::CEDROOMPOOLCDSignal::CEDROOMPOOLCDSignal(unsigned int elemCount, CDSignal* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDSignal)){;}

CDSignal *	CASSI::EDROOMTopContext::CEDROOMPOOLCDSignal::AllocData(){
	return(CDSignal*)CEDROOMProtectedMemoryPool::AllocData();
}

	//CEDROOMPOOLCDFrame

CASSI::EDROOMTopContext::CEDROOMPOOLCDFrame::CEDROOMPOOLCDFrame(unsigned int elemCount, CDFrame* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDFrame)){;}

CDFrame *	CASSI::EDROOMTopContext::CEDROOMPOOLCDFrame::AllocData(){
	return(CDFrame*)CEDROOMProtectedMemoryPool::AllocData();
}



// ***********************************************************************

// class EDROOMTopState

// ***********************************************************************



	// CONSTRUCTOR*************************************************

CASSI::EDROOMTopState::EDROOMTopState (CASSI &act, CEDROOMMemory *pEDROOMMemory  ):
	  EDROOMTopContext( act , VBidirectional, VCrcOk, VDataFrame, VFrameType, VSignalFrame,EDROOMPoolCDSignal,EDROOMPoolCDFrame )
	, VBidirectional ( false )
	, VCrcOk ( false )
	, VDataFrame (   )
	, VFrameType ( FrameTypeIsSSIDefault )
	, VSignalFrame (   )
	, EDROOMPoolCDSignal ( 3, pEDROOMMemory->poolCDSignal, pEDROOMMemory->poolMarkCDSignal)
	, EDROOMPoolCDFrame ( 3, pEDROOMMemory->poolCDFrame, pEDROOMMemory->poolMarkCDFrame)
{

}

	// EDROOMBehaviour**********************************************

void CASSI::EDROOMTopState::EDROOMBehaviour(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans = EDROOMIllegada();

	do{

		switch(edroomCurrentTrans.localId){

			case(Init):
				edroomNextState = Standby;
				break;
			case(ToListening):
				FToListening();
				edroomNextState = Listening;
				break;
			case(ReceiveData):
				FReceiveData();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( GIsData() ){
					FSendToStoreFrame();
					edroomCurrentTrans.localId = ReceiveData_IsData;
					edroomNextState = DeliveryServer;
				 } 
				else if( GIsUnidirectional() ){
					FSendFrameUnidirectional();
					edroomCurrentTrans.localId = ReceiveData_IsUnidirectional;
					edroomNextState = Listening;
				 } 
				else{
					FMsgCommited();
					edroomCurrentTrans.localId = ReceiveData_CrcFail;
					edroomNextState = Listening;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
			case(ReceiveSignal):
				FReceiveSignal();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( GIsAck() ){
					FDataConfirmed();
					edroomCurrentTrans.localId = ReceiveSignal_IsAck;
					edroomNextState = Listening;
				 } 
				else if( GIsDiscovery() ){
					edroomCurrentTrans.localId = ReceiveSignal_IsDiscovery;
					edroomNextState = DeliveryServer;
				 } 
				else{
					FMsgCommited();
					edroomCurrentTrans.localId = ReceiveSignal_CrcFail;
					edroomNextState = Listening;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
			case(MoreData):
				FMoreData();
				edroomNextState = Listening;
				break;
			case(NoMoreData):
				FNoMoreData();
				edroomNextState = Listening;
				break;
			case(ToStandby):
				edroomNextState = Standby;
				break;
		}

		EDROOMcomponent.EDROOMTraceStateEntry();

		EDROOMcomponent.EDROOMTraceStateEntry();

		switch(edroomNextState){

			case(I):
				edroomCurrentTrans=EDROOMIllegada();
				break;

			case(Listening):
				
				edroomCurrentTrans=EDROOMListeningllegada();
				break;

			case(DeliveryServer):
				FRequestNextFrame();
				edroomCurrentTrans=EDROOMDeliveryServerllegada();
				break;

			case(Standby):
				edroomCurrentTrans=EDROOMStandbyllegada();
				break;

		}

		EDROOMcomponent.EDROOMTraceStateExit();

		edroomCurrentState=edroomNextState;

	}while(Msg->signal != EDROOMSignalDestroy);

}



	// Inicio**********************************************

void CASSI::EDROOMTopState::EDROOMInicio(){

edroomCurrentState=I;

}



//	 ***********************************************************************

//	 llegada SubEstado I

//	 ***********************************************************************



TEDROOMTransId CASSI::EDROOMTopState::EDROOMIllegada(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans.localId = Init;
	edroomCurrentTrans.distanceToContext = 0;
	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, 0);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja Listening

	// ***********************************************************************



TEDROOMTransId CASSI::EDROOMTopState::EDROOMListeningllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (SDataFrame): 

				 if ( *Msg->GetPInterface() == Ssi) {

					edroomCurrentTrans.localId = ReceiveData;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

			case (SSignalFrame): 

				 if ( *Msg->GetPInterface() == Ssi) {

					edroomCurrentTrans.localId = ReceiveSignal;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

			case (SToStandBy): 

				 if ( *Msg->GetPInterface() == SsiCtrl) {

					edroomCurrentTrans.localId= ToStandby;
					edroomCurrentTrans.distanceToContext = 0;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja DeliveryServer

	// ***********************************************************************



TEDROOMTransId CASSI::EDROOMTopState::EDROOMDeliveryServerllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (SDataFrame): 

				 if ( *Msg->GetPInterface() == StoreAndNextFrame) {

					edroomCurrentTrans.localId= MoreData;
					edroomCurrentTrans.distanceToContext = 0;
					edroomValidMsg=true;
				 }

				break;

			case (SSignalFrame): 

				 if ( *Msg->GetPInterface() == StoreAndNextFrame) {

					edroomCurrentTrans.localId= NoMoreData;
					edroomCurrentTrans.distanceToContext = 0;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja Standby

	// ***********************************************************************



TEDROOMTransId CASSI::EDROOMTopState::EDROOMStandbyllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (SToListening): 

				 if ( *Msg->GetPInterface() == SsiCtrl) {

					edroomCurrentTrans.localId= ToListening;
					edroomCurrentTrans.distanceToContext = 0;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



